using System.Runtime.InteropServices;

namespace Making.Avalonia.WebView.Linux.Native;

internal static class WebKitGtkInterop
{
    private const string WebKit2_41 = "libwebkit2gtk-4.1.so.0";
    private const string WebKit2_40 = "libwebkit2gtk-4.0.so.37";
    private const string Gtk3 = "libgtk-3.so.0";
    private const string GObject = "libgobject-2.0.so.0";
    private const string GLib = "libglib-2.0.so.0";
    private const string Gdk3 = "libgdk-3.so.0";

    private const string WebKit2 = WebKit2_41;

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_web_view_new")]
    public static extern IntPtr webkit_web_view_new();

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_web_view_new_with_user_content_manager")]
    public static extern IntPtr webkit_web_view_new_with_user_content_manager(IntPtr user_content_manager);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_web_view_load_uri")]
    public static extern void webkit_web_view_load_uri(IntPtr web_view, string uri);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_web_view_load_html")]
    public static extern void webkit_web_view_load_html(IntPtr web_view, string content, string base_uri);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_web_view_reload")]
    public static extern void webkit_web_view_reload(IntPtr web_view);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_web_view_stop_loading")]
    public static extern void webkit_web_view_stop_loading(IntPtr web_view);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_web_view_can_go_back")]
    public static extern bool webkit_web_view_can_go_back(IntPtr web_view);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_web_view_can_go_forward")]
    public static extern bool webkit_web_view_can_go_forward(IntPtr web_view);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_web_view_go_back")]
    public static extern void webkit_web_view_go_back(IntPtr web_view);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_web_view_go_forward")]
    public static extern void webkit_web_view_go_forward(IntPtr web_view);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_web_view_get_uri")]
    public static extern string webkit_web_view_get_uri(IntPtr web_view);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_web_view_set_zoom_level")]
    public static extern void webkit_web_view_set_zoom_level(IntPtr web_view, double zoom_level);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_web_view_get_zoom_level")]
    public static extern double webkit_web_view_get_zoom_level(IntPtr web_view);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_web_view_run_javascript")]
    public static extern void webkit_web_view_run_javascript(IntPtr web_view, string script, IntPtr cancellable, IntPtr callback, IntPtr user_data);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_web_view_get_settings")]
    public static extern IntPtr webkit_web_view_get_settings(IntPtr web_view);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_web_view_set_settings")]
    public static extern void webkit_web_view_set_settings(IntPtr web_view, IntPtr settings);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_settings_new")]
    public static extern IntPtr webkit_settings_new();

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_settings_set_enable_developer_extras")]
    public static extern void webkit_settings_set_enable_developer_extras(IntPtr settings, bool enabled);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_settings_get_enable_developer_extras")]
    public static extern bool webkit_settings_get_enable_developer_extras(IntPtr settings);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_settings_set_enable_javascript")]
    public static extern void webkit_settings_set_enable_javascript(IntPtr settings, bool enabled);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_settings_set_javascript_can_access_clipboard")]
    public static extern void webkit_settings_set_javascript_can_access_clipboard(IntPtr settings, bool enabled);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_settings_set_enable_media_stream")]
    public static extern void webkit_settings_set_enable_media_stream(IntPtr settings, bool enabled);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_settings_set_enable_smooth_scrolling")]
    public static extern void webkit_settings_set_enable_smooth_scrolling(IntPtr settings, bool enabled);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_settings_set_allow_file_access_from_file_urls")]
    public static extern void webkit_settings_set_allow_file_access_from_file_urls(IntPtr settings, bool enabled);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_settings_set_disable_web_security")]
    public static extern void webkit_settings_set_disable_web_security(IntPtr settings, bool disabled);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_settings_set_user_agent")]
    public static extern void webkit_settings_set_user_agent(IntPtr settings, string user_agent);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_user_content_manager_new")]
    public static extern IntPtr webkit_user_content_manager_new();

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_user_content_manager_register_script_message_handler")]
    public static extern void webkit_user_content_manager_register_script_message_handler(IntPtr manager, string name);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_user_script_new")]
    public static extern IntPtr webkit_user_script_new(string source, int inject_frames, int inject_time, IntPtr allow_list, IntPtr block_list);

    [DllImport(WebKit2, CallingConvention = CallingConvention.Cdecl, EntryPoint = "webkit_user_content_manager_add_script")]
    public static extern void webkit_user_content_manager_add_script(IntPtr manager, IntPtr script);

    [DllImport(Gtk3, CallingConvention = CallingConvention.Cdecl, EntryPoint = "gtk_init_check")]
    public static extern bool gtk_init_check(int argc, string[] argv);

    [DllImport(Gtk3, CallingConvention = CallingConvention.Cdecl, EntryPoint = "gtk_window_new")]
    public static extern IntPtr gtk_window_new(int type);

    [DllImport(Gtk3, CallingConvention = CallingConvention.Cdecl, EntryPoint = "gtk_container_add")]
    public static extern void gtk_container_add(IntPtr container, IntPtr widget);

    [DllImport(Gtk3, CallingConvention = CallingConvention.Cdecl, EntryPoint = "gtk_widget_show_all")]
    public static extern void gtk_widget_show_all(IntPtr widget);

    [DllImport(Gtk3, CallingConvention = CallingConvention.Cdecl, EntryPoint = "gtk_widget_hide")]
    public static extern void gtk_widget_hide(IntPtr widget);

    [DllImport(Gtk3, CallingConvention = CallingConvention.Cdecl, EntryPoint = "gtk_widget_destroy")]
    public static extern void gtk_widget_destroy(IntPtr widget);

    [DllImport(Gtk3, CallingConvention = CallingConvention.Cdecl, EntryPoint = "gtk_widget_get_window")]
    public static extern IntPtr gtk_widget_get_window(IntPtr widget);

    [DllImport(Gtk3, CallingConvention = CallingConvention.Cdecl, EntryPoint = "gtk_widget_realize")]
    public static extern void gtk_widget_realize(IntPtr widget);

    [DllImport(Gtk3, CallingConvention = CallingConvention.Cdecl, EntryPoint = "gtk_window_set_default_size")]
    public static extern void gtk_window_set_default_size(IntPtr window, int width, int height);

    [DllImport(Gtk3, CallingConvention = CallingConvention.Cdecl, EntryPoint = "gtk_window_resize")]
    public static extern void gtk_window_resize(IntPtr window, int width, int height);

    [DllImport(Gtk3, CallingConvention = CallingConvention.Cdecl, EntryPoint = "gtk_widget_set_size_request")]
    public static extern void gtk_widget_set_size_request(IntPtr widget, int width, int height);

    [DllImport(Gdk3, CallingConvention = CallingConvention.Cdecl, EntryPoint = "gdk_x11_window_get_xid")]
    public static extern IntPtr gdk_x11_window_get_xid(IntPtr window);

    [DllImport(Gdk3, CallingConvention = CallingConvention.Cdecl, EntryPoint = "gdk_window_get_geometry")]
    public static extern void gdk_window_get_geometry(IntPtr window, out int x, out int y, out int width, out int height);

    [DllImport(GObject, CallingConvention = CallingConvention.Cdecl, EntryPoint = "g_signal_connect_data")]
    public static extern IntPtr g_signal_connect_data(IntPtr instance, string detailed_signal, IntPtr c_handler, IntPtr data, IntPtr destroy_data, int connect_flags);

    [DllImport(GObject, CallingConvention = CallingConvention.Cdecl, EntryPoint = "g_object_unref")]
    public static extern void g_object_unref(IntPtr obj);

    [DllImport(GObject, CallingConvention = CallingConvention.Cdecl, EntryPoint = "g_object_ref")]
    public static extern IntPtr g_object_ref(IntPtr obj);

    [DllImport(GLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "g_idle_add")]
    public static extern IntPtr g_idle_add(IntPtr function, IntPtr data);

    [DllImport(GLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "g_main_context_iteration")]
    public static extern bool g_main_context_iteration(IntPtr context, bool may_block);

    [DllImport(GLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "g_main_context_default")]
    public static extern IntPtr g_main_context_default();

    [DllImport(GLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "g_free")]
    public static extern void g_free(IntPtr mem);

    [DllImport(GLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "g_strdup")]
    public static extern IntPtr g_strdup(string str);

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void ScriptMessageCallback(IntPtr user_content_manager, IntPtr js_result, IntPtr user_data);

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void NavigationCallback(IntPtr web_view, IntPtr navigation_action, IntPtr user_data);

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate bool IdleCallback(IntPtr user_data);

    public static IntPtr ConnectSignal(IntPtr instance, string signal, Delegate handler, IntPtr userData = default)
    {
        var handlerPtr = Marshal.GetFunctionPointerForDelegate(handler);
        return g_signal_connect_data(instance, signal, handlerPtr, userData, IntPtr.Zero, 0);
    }

    public const int GTK_WINDOW_TOPLEVEL = 0;
    public const int WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES = 0;
    public const int WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START = 0;
}